/*
 * Decoder.cpp
 *
 *  Created on: 2011-2-27
 *      Author: hao
 */

#include "Decoder.h"
#include "Error.h"
#include <unistd.h>
#include <dlfcn.h>

Decoder::Decoder(const char * szPath) : patch(szPath), decoderHandle(NULL) {
}

Decoder::~Decoder() {

    CheckingFunction = NULL;

    Decoding = NULL;

    SetTrack = NULL;

    getSoundSampleStatus = NULL;

    Seek = NULL;

    if (decoderdestroy)
        decoderdestroy();

    decoderinit = NULL;
    decoderdestroy = NULL;

    if (decoderHandle) {
        dlclose(decoderHandle);
        decoderHandle = NULL;
    }

}

bool( * Decoder::getCheckingFunction())(void *, unsigned long long) {

    return CheckingFunction;

}

bool( * Decoder::getSoundStatusFunction())(unsigned *, unsigned *, unsigned *) {

    return getSoundSampleStatus;

}

bool( * Decoder::getDecodingFunction())(void *, size_t, size_t *) {

    return Decoding;

}

bool( * Decoder::getSetTrack())(int, int, int, int, int, int) {
    return SetTrack;
}

bool( * Decoder::getSeek())(int, int, int) {
    return Seek;
}

void( *Decoder::getTotalTime())(int *, int *, int*) {
    return TotalTime;
}

bool Decoder::Init() {

    if (decoderHandle) return false;

    if (access(patch.c_str(), F_OK) == -1) {

        throw Error(ErrorTag::DECODER_PLUGIN_DISAPPEAR);

    }

    decoderHandle = dlopen(patch.c_str(), RTLD_LAZY);

    //const char * str = dlerror();

    if (!decoderHandle) throw Error(ErrorTag::DECODER_LOADING_ERROR);

    CheckingFunction = (bool( *)(void *, unsigned long long))dlsym(decoderHandle, "Checking");

    Decoding = (bool( *)(void *, size_t, size_t *))dlsym(decoderHandle, "Decoding");

    SetTrack = (bool( *)(int, int, int, int, int, int))dlsym(decoderHandle, "SetTrack");

    getSoundSampleStatus = (bool( *)(unsigned *, unsigned *, unsigned *))dlsym(decoderHandle, "getStatus");

    Seek = (bool(*)(int, int, int))dlsym(decoderHandle, "Seek");

    TotalTime = (void(*)(int *, int *, int *))dlsym(decoderHandle, "getTotalTime");

    decoderinit = (void(*)())dlsym(decoderHandle, "Init");

    decoderdestroy = (void(*)())dlsym(decoderHandle, "Destroy");

    const char * (* GetPrefixName)();

    GetPrefixName = (const char * (*)())dlsym(decoderHandle, "prefixSurport");

    if (GetPrefixName)
        prefixName = GetPrefixName();

    if (!CheckingFunction || !Decoding || !getSoundSampleStatus || !SetTrack || !Seek || !TotalTime || (bool(decoderinit) ^ bool( decoderdestroy)) != 0) {
        dlclose(decoderHandle);
        CheckingFunction = NULL;

        Decoding = NULL;

        SetTrack = NULL;

        getSoundSampleStatus = NULL;

        Seek = NULL;

        TotalTime = NULL;

        decoderinit = NULL;

        decoderdestroy = NULL;
        
        return false;
    }

    if (decoderinit)
        decoderinit();

    return true;

}

const std::string & Decoder::getPrefixName() const {

    return prefixName;

}


